from shapely.geometry import Point, Polygon  # shapely用于2D判断
import matplotlib.pyplot as plt  # 可视化


# 函数：解析输入坐标字符串为元组（支持XYZ或经纬高，返回所有三个值）
def parse_point(input_str, coord_type):
    parts = [float(p.strip()) for p in input_str.split(',')]
    if len(parts) != 3:
        raise ValueError("输入格式错误！需输入3个数字，用逗号分隔（如: 116.390,39.910,0）。")
    if coord_type == 'latlon':
        return (parts[1], parts[0], parts[2])  # (lon, lat, alt)
    elif coord_type == 'xyz':
        return (parts[0], parts[1], parts[2])  # (x, y, z)
    else:
        raise ValueError("未知坐标类型！")


# 函数：判断点是否在围栏内（2D，只用前两个坐标）
def check_in_fence(point, polygon, include_boundary=False):
    p = Point(point[:2])
    if include_boundary:
        return p.intersects(polygon)  # 包括边界
    else:
        return p.within(polygon)  # 不包括边界


# 函数：可视化（只用前两个坐标，标签显示第三个值）
def visualize(polygon, test_points, inside_status):
    poly_x = [coord[0] for coord in polygon.exterior.coords]
    poly_y = [coord[1] for coord in polygon.exterior.coords]
    plt.plot(poly_x, poly_y, color='blue', label='电子围栏')

    for i, point in enumerate(test_points):
        color = 'green' if inside_status[i] else 'red'
        plt.scatter(point[0], point[1], color=color, s=50, label=f'点{i + 1} (高度:{point[2]:.2f})')

    plt.xlabel('X (lon/x)')
    plt.ylabel('Y (lat/y)')
    plt.title('2D电子围栏判断可视化')
    plt.legend()
    plt.grid(True)
    plt.show()


# 主程序
if __name__ == "__main__":
    print("欢迎使用交互式2D GNSS电子围栏判断工具（带调试）！")

    # 步骤1: 选择坐标类型
    coord_type = input("输入坐标类型 (latlon 为经纬高, xyz 为XYZ): ").strip().lower()
    if coord_type not in ['latlon', 'xyz']:
        print("无效类型！默认使用latlon。")
        coord_type = 'latlon'
    label = "经纬高 (lat,lon,alt)" if coord_type == 'latlon' else "XYZ (x,y,z)"

    # 新增：选择是否包括边界
    include_boundary = input("是否包括边界点为内部？(yes/no，默认no): ").strip().lower() == 'yes'
    print(f"边界判断: {'包括' if include_boundary else '不包括'}")

    # 步骤2: 输入围栏边界点
    print(f"\n输入围栏边界点（{label}格式，用逗号分隔）。输入至少3个点，按顺序形成闭合多边形（支持不规则形状）。")
    print("每次输入一个点，回车确认；输入 'done' 结束。确保点顺序顺时针/逆时针，不自交！")
    fence_points = []
    while True:
        inp = input("围栏点: ").strip()
        if inp.lower() == 'done':
            break
        try:
            point = parse_point(inp, coord_type)
            fence_points.append(point[:2])  # 只存前两个用于Polygon
            print(f"添加点: {point}")  # 显示完整三个值
        except ValueError as e:
            print(f"错误: {e} 请重新输入。")

    if len(fence_points) < 3:
        print("错误: 至少需要3个点形成多边形！程序退出。")
        exit()

    # 创建多边形并检查有效性
    fence_polygon = Polygon(fence_points)
    if not fence_polygon.is_valid:
        print("警告: 多边形无效（可能自交或顺序错）！所有点将判外部。请检查点顺序。")
    else:
        print("多边形有效！面积:", fence_polygon.area)
    print("\n围栏定义完成！多边形点 (忽略高度):", fence_points)

    # 步骤3: 输入测试点并判断（加调试）
    test_points = []
    inside_status = []
    print("\n现在输入测试点（相同格式）。每次一个点，回车确认；输入 'done' 结束并可视化。")
    while True:
        inp = input("测试点: ").strip()
        if inp.lower() == 'done':
            break
        try:
            point = parse_point(inp, coord_type)
            is_inside = check_in_fence(point, fence_polygon, include_boundary)
            status = "在围栏内部" if is_inside else "在围栏外部"
            p = Point(point[:2])
            dist_to_boundary = p.distance(fence_polygon.boundary)
            print(f"点 {point}: {status} | 距边界距离: {dist_to_boundary:.6f}（如果很小但外部，可能边界/精度问题）")
            test_points.append(point)
            inside_status.append(is_inside)
        except ValueError as e:
            print(f"错误: {e} 请重新输入。")

    # 步骤4: 可视化所有测试点（如果有）
    if test_points:
        visualize(fence_polygon, test_points, inside_status)
    else:
        print("无测试点，无可视化。")

    print("程序结束。再次运行可重试！")